package cn.edu.sjtu.se.dslab.component.design.generate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.log4j.Logger;

import cn.edu.sjtu.se.dslab.component.design.Button;
import cn.edu.sjtu.se.dslab.component.design.generate.element.DynamicVar;
import cn.edu.sjtu.se.dslab.component.design.generate.element.ElementType;
import cn.edu.sjtu.se.dslab.component.design.generate.element.Line;
import cn.edu.sjtu.se.dslab.component.design.generate.element.PageElement;
import cn.edu.sjtu.se.dslab.component.design.generate.element.PageElementParseUtil;
import cn.edu.sjtu.se.dslab.component.design.generate.element.PageVariable;
import cn.edu.sjtu.se.dslab.component.design.generate.element.Point;
import cn.edu.sjtu.se.dslab.component.design.generate.element.Rectangle;
import cn.edu.sjtu.se.dslab.component.design.generate.element.StaticString;
import cn.edu.sjtu.se.dslab.component.dp.parse.DesignPatternInstanceBean;
import cn.edu.sjtu.se.dslab.component.dp.parse.Property;
import cn.edu.sjtu.se.dslab.component.method.InterfaceMethod;
import cn.edu.sjtu.se.dslab.component.method.MethodComponent;
import cn.edu.sjtu.se.dslab.component.method.util.MethodComponentUtil;
import cn.edu.sjtu.se.dslab.helper.ApplicationContextHelpler;
import cn.edu.sjtu.se.dslab.project.DisplayZone;
import cn.edu.sjtu.se.dslab.project.Project;
import cn.edu.sjtu.se.dslab.project.Variable;
import cn.edu.sjtu.se.dslab.service.IButtonService;
import cn.edu.sjtu.se.dslab.service.IDisplayZoneService;
import cn.edu.sjtu.se.dslab.service.IInterfaceMethodService;
import cn.edu.sjtu.se.dslab.service.IMethodComponentService;
import cn.edu.sjtu.se.dslab.service.IVariableService;
import cn.edu.sjtu.se.dslab.util.FileUtil;
import cn.edu.sjtu.se.dslab.util.MapComparaor;
import cn.edu.sjtu.se.dslab.util.StringUtil;

public class ViewCodeGenerator extends DesignPatternCodeGenerator {

	private static final Logger logger = Logger
			.getLogger(ViewCodeGenerator.class);

	IButtonService buttonService;
	IInterfaceMethodService interfaceMethodService;

	private static final String VIEW_HEADER_TEMPLATE_NAME = "view_h.vm";
	private static final String VIEW_SOURCE_TEMPLATE_NAME = "view_c.vm";

	private final String VIEW_HEADER_FILE_NAME;
	private final String VIEW_SOURCE_FILE_NAME;

	// first char is lowerCase
	private final String L_VIEW_NAME;
	// first char is upperCase
	private final String U_VIEW_NAME;

	private final String VIEW_NAME;

	private Map<String, Property> properties;

	private MethodComponentUtil methodComponentUtil;

	private IMethodComponentService methodComponentService;
	
	private IVariableService variableService;
	
	private IDisplayZoneService displayZoneService;

	private Set<String> dependencyFileSet;
	
	Map<String, String> methodComponentFiles;

	public ViewCodeGenerator(String viewName) {
		VIEW_NAME = viewName;
		L_VIEW_NAME = StringUtil.lowerFirstChar(viewName);
		U_VIEW_NAME = StringUtil.upperFirstChar(viewName);
		StringBuilder viewHeaderFileName = new StringBuilder("View_").append(
				U_VIEW_NAME).append(".h");
		VIEW_HEADER_FILE_NAME = viewHeaderFileName.toString();
		StringBuilder viewSourceFileName = new StringBuilder("View_").append(
				U_VIEW_NAME).append(".c");
		VIEW_SOURCE_FILE_NAME = viewSourceFileName.toString();

		buttonService = (IButtonService) ApplicationContextHelpler.getBean("buttonService");
		interfaceMethodService = (IInterfaceMethodService) ApplicationContextHelpler.getBean("interfaceMethodService");

		methodComponentService = (IMethodComponentService) ApplicationContextHelpler.getBean("methodComponentService");

		methodComponentUtil = (MethodComponentUtil) ApplicationContextHelpler.getBean("methodComponentUtil");
		
		variableService = (IVariableService)ApplicationContextHelpler.getBean("variableService");
		
		displayZoneService = (IDisplayZoneService)ApplicationContextHelpler.getBean("displayZoneService");

		dependencyFileSet = new HashSet<String>();
		methodComponentFiles = new HashMap<String, String>();
	}

	@Override
	public void generateCode(String targetDirPath, Project project, 
			DesignPatternInstanceBean... dpiBean) throws IOException {

		inputData("L_ViewName", L_VIEW_NAME);
		inputData("U_ViewName", U_VIEW_NAME);

		properties = dpiBean[0].getInstanceByName("page_name", VIEW_NAME);
		
		String pageType = properties.get("page_type").getValue();
		if (pageType.equals("userDefineDF")){
			Map<String, List> elementMap = parsePageElements(properties
					.get("page_elements").getValue());
			inputData("staticStringElements", elementMap.get(ElementType.STATIC_STRING.toString()));
			inputData("enterElements", elementMap.get(ElementType.POINT.toString()));
			inputData("dynamicVarElements", elementMap.get(ElementType.DYNAMIC_VAR.toString()));
			inputData("lineElements", elementMap.get(ElementType.LINE.toString()));
			inputData("rectangleElements", elementMap.get(ElementType.RECTANGLE.toString()));
			//统计所有的变量
			Set<Long> variableIds = new HashSet<Long>();
			for (Object pe: elementMap.get(ElementType.DYNAMIC_VAR.toString())){
				variableIds.add(((DynamicVar)pe).getVarId());
			}
			Set<Variable> variables = new HashSet<Variable>();
			for (Long vId: variableIds){
				Variable var = variableService.getVariableById(vId);
				if (null == var) continue;
				variables.add(var);
			}
			inputData("variables", variables);

			// responses entry
			List<Map<String, Property>> responseEntrys = parseResponseEntrys(dpiBean[1].getInstances());
			inputData("responseEntrys", responseEntrys);
			inputData("isMain", properties.get("is_main").getValue());
			logger.info("IsMain:" + properties.get("is_main").getValue() + properties.get("page_name").getValue());
			
			//
			List<String> pageNameList = new ArrayList<String>();
			for (Map<String, Property> m : responseEntrys){
				if (m.get("type").getValue().equals("jump")){
					pageNameList.add(StringUtil.upperFirstChar(m.get("target_page").getValue()));
				}
			}
			inputData("pageNameList", pageNameList);
		}else if (pageType.equals("pageData")){
			List<PageVariable> pageVariables = parsePageVariables(properties.get("page_variables").getValue());
			inputData("pageVariables", pageVariables);
			inputData("isMain", properties.get("is_main").getValue());
			
			//拷贝所有依赖的文件
			StringBuffer devicePath = new StringBuffer(FileUtil.getRootPath());
			devicePath.append(targetDirPath).append("Devices");
			FileUtil.copyFileList(new HashSet<String>(methodComponentFiles.values()), devicePath.toString());
		}
		

		// relative path
		StringBuffer viewSourceFile = new StringBuffer(targetDirPath)
				.append("/App/")
				.append(VIEW_SOURCE_FILE_NAME);
		StringBuffer viewHeaderFile = new StringBuffer(targetDirPath)
				.append("/App/")
				.append(VIEW_HEADER_FILE_NAME);

		generateCodeFile(viewHeaderFile.toString(), VIEW_HEADER_TEMPLATE_NAME);
		generateCodeFile(viewSourceFile.toString(), VIEW_SOURCE_TEMPLATE_NAME);
	}

	private Map<String, List> parsePageElements(String elementString) {
		String[] elements = elementString.split("\\|");
		Map<String, List> elementMap = new HashMap<String, List>();
		List<StaticString> staticPageELements = new ArrayList<StaticString>();
		List<Point> enterPageElements = new ArrayList<Point>();
		List<DynamicVar> dynamicVarElements = new ArrayList<DynamicVar>();
		List<Line> lineElements = new ArrayList<Line>();
		List<Rectangle> rectangleElements = new ArrayList<Rectangle>();
		
		for (String e : elements) {
			PageElement pe = PageElementParseUtil.parsePageElement(e);
			if (pe != null) {
				if (pe.getElementType() == ElementType.STATIC_STRING) {
					staticPageELements.add((StaticString) pe);
				}else if (pe.getElementType() == ElementType.POINT){
					enterPageElements.add((Point) pe );
				}else if (pe.getElementType() == ElementType.DYNAMIC_VAR){
					dynamicVarElements.add((DynamicVar)pe);
				}else if (pe.getElementType() == ElementType.LINE){
					lineElements.add((Line)pe);
				}else if (pe.getElementType() == ElementType.RECTANGLE){
					rectangleElements.add((Rectangle)pe);
				}
			}
		}
		elementMap.put(ElementType.STATIC_STRING.toString(), staticPageELements);
		elementMap.put(ElementType.POINT.toString(), enterPageElements);
		elementMap.put(ElementType.DYNAMIC_VAR.toString(), dynamicVarElements);
		elementMap.put(ElementType.RECTANGLE.toString(), rectangleElements);
		elementMap.put(ElementType.LINE.toString(), lineElements);
		
		return elementMap;
	}
	
	private List<PageVariable> parsePageVariables(String variableString){
		String[] variables = variableString.split("\\|");
		List<PageVariable> pvs = new ArrayList<PageVariable>();
		for (String v: variables){
			if (v == null || v.equals("")) continue;
			logger.info(v);
			String[] temp = v.split(";");
			if(temp.length!= 5) continue;
			
			PageVariable pv = new PageVariable();
			pv.setCode(Integer.parseInt(temp[2]));
			DisplayZone dz = displayZoneService.getDisplayZoneById(Long.parseLong(temp[1]));
			if (dz == null) continue;
			pv.setDisplayZoneName(dz.getName());
			for (String s: temp){
				logger.info("temp:" + s);
			}
			
			InterfaceMethod im = interfaceMethodService.getInterfaceMethodById(Long.parseLong(temp[3]));
			MethodComponent mc = methodComponentService.getMethodComponentByUri(temp[4]);
			
			//获取函数组件的实现文件及其依赖文件
			Map<String, String> methodFiles = null;
			try {
				methodFiles = methodComponentUtil.getMethodComponentFileList(mc);
			} catch (IOException e) {
				e.printStackTrace();
			}
			methodComponentFiles.putAll(methodFiles);
			
			pv.setDrawMethodName(im.getName());
			pvs.add(pv);
		}
		return pvs;
	}

	private List<Map<String, Property>> parseResponseEntrys(
			List<Map<String, Property>> instances) {
		List<Map<String, Property>> responseEntrys = new ArrayList<Map<String, Property>>();
		for (Map<String, Property> instance : instances) {
			if (instance.get("page").getValue().equals(VIEW_NAME)) {
				Button button = buttonService.getButtonById(Long
						.parseLong(instance.get("button").getValue()));
				instance.get("button").setValue(button.getName());
				instance.put("buttonCode", new Property());
				instance.get("buttonCode").setValue(button.getCode());
				if (instance.get("type").getValue().equals("function")) {
					InterfaceMethod controlFunction = interfaceMethodService
							.getInterfaceMethodById(Long.parseLong(instance
									.get("control_function").getValue()
									.split("=")[0])); // the [0] is interface Id
					instance.get("control_function").setValue(
							controlFunction.getName() + "("
									+ controlFunction.getArguments() + ")");
				} else {
					logger.info(instance.entrySet());
					instance.get("target_page").setValue(
							StringUtil.lowerFirstChar(instance.get("target_page").getValue()));
				}
				responseEntrys.add(instance);
			}
		}
		Collections.sort(responseEntrys,new MapComparaor());
		for (Map<String, Property> map : responseEntrys) {
			for (Entry<String, Property> e : map.entrySet()) {
				logger.info("[" + e.getKey() + "]" + "="
						+ e.getValue().getValue() + "]");
			}
		}
		return responseEntrys;
	}

}
